package console;

import javax.swing.JTextPane;
import javax.swing.text.*;
import java.awt.Font;
import java.awt.Color;

public class ANSIOutputBox {

    private JTextPane outputBox;
    private DefaultStyledDocument document;
    private Color defaultColor = new Color(204, 204, 204);
    private Color currentColor = defaultColor;
    private boolean bold = false;
    private int fontSize;

    public ANSIOutputBox(JTextPane textPane) {
        this.outputBox = textPane;
        fontSize = 14;
        document = new DefaultStyledDocument();
        outputBox.setDocument(document);
    }

    // Adds text to the output box in ANSI formatting
    public void addANSIText(String input) {
        if (input.length() < 2) {
            printToConsole(input, currentColor);
        } else {
            String[] words = input.split("(?=\\" + (char) 27 + ")");

            for (int x = 0; x < words.length; x++) {
                if (words[x].length() > 0) {
                    // If no escape code, print the word with current formatting
                    if (words[x].charAt(0) != (char) 27) {
                        printToConsole(words[x], currentColor);
                    } else {
                        // Otherwise, get the escape code if it's not invalid, otherwise skip
                        if (words[x].length() > 2 && words[x].charAt(1) == '[') {
                            // Start after the [ and get all the digits
                            int y = 2;
                            while (y != words[x].length() && words[x].charAt(y) != 'm') {
                                y++;
                            }

                            // As long as it was formatted okay to the end, print it
                            if (y != words[x].length()) {
                                String[] allCodes = words[x].substring(2, y).split(";");

                                for (int c = 0; c < allCodes.length; c++) {
                                    setFormatAndColour(getEscapeCode(allCodes[c]));
                                }
                                printToConsole(words[x].substring(y + 1), currentColor);
                            }
                        }
                    }
                }
            }
        }
        scrollToBottom();
    }

    private void printToConsole(String input, Color c) {
        SimpleAttributeSet aset = new SimpleAttributeSet();
        StyleConstants.setForeground(aset, c);

        try {
            document.insertString(document.getLength(), input, aset);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }

    }

    private void setFormatAndColour(int colorCode) {
        if (colorCode == 1) {
            bold = true;
        } else if (colorCode == 0) {
            bold = false;
        } else if (colorCode == 30) {
            // Black
            currentColor = Color.black;
        } else if (colorCode == 31) {
            // Red
            if (bold) {
                currentColor = Color.red;
            } else {
                currentColor = new Color(176, 23, 31);
            }
        } else if (colorCode == 32) {
            // Green
            if (bold) {
                currentColor = Color.green;
            } else {
                currentColor = new Color(0, 100, 0);
            }
        } else if (colorCode == 33) {
            // Yellow
            if (bold) {
                currentColor = new Color(242, 233, 18);
            } else {
                currentColor = new Color(205, 173, 0);
            }
        } else if (colorCode == 34) {
            // Blue
            if (bold) {
                currentColor = Color.blue;
            } else {
                currentColor = new Color(0, 0, 120);
            }
        } else if (colorCode == 35) {
            // Magenta
            if (bold) {
                currentColor = Color.magenta;
            } else {
                currentColor = new Color(139, 0, 139);
            }
        } else if (colorCode == 36) {
            // Cyan
            if (bold) {
                currentColor = Color.cyan;
            } else {
                currentColor = new Color(0, 139, 139);
            }
        } else if (colorCode == 37) {
            if (bold) {
                currentColor = Color.white;
            } else {
                currentColor = defaultColor;
            }
        } else if (colorCode == 39) {
            currentColor = defaultColor;
        }
    }

    // Returns rescape code. Returns -1 if error.
    private int getEscapeCode(String code) {
        return Integer.parseInt(code);
    }

    public void updateFontSize(boolean increase) {
        if (increase) {
            fontSize++;
        } else {
            fontSize--;
        }
        Font boxFont = new Font("Monospaced", 0, fontSize);
        outputBox.setFont(boxFont);
        scrollToBottom();
    }

    public void scrollToBottom() {
        outputBox.setCaretPosition(document.getLength());
    }
}
